﻿using System;
using System.Collections.Generic;
using System.Text;

namespace vJine.Core.Base {
    public class TreeMap {
        public TreeMap() {
            this.Index = -1;
        }

        public TreeMap prev { get; private set; }
        public TreeMap next { get; private set; }

        List<TreeMap> Next { get; set; }

        byte? Key { get; set; }
        public int Index { get; private set; }

        public object Value { get; protected set; }

        public bool IsBoundary { get; private set; }

        TreeMap Create(byte b, TreeMap chain) {
            if (chain.Key == null && chain.Next == null) {
                chain.Key = b;
                chain.next = new TreeMap();
                chain.next.prev = chain;

                return chain.next;
            } else if (chain.Key != null && chain.Next == null) {
                if (chain.Key == b) {
                    if (chain.next == null) {
                        chain.next = new TreeMap();
                        chain.next.prev = chain;
                    }
                    return chain.next;
                } else {
                    List<TreeMap> _Next = new List<TreeMap>();
                    TreeMap newChain = new TreeMap() { Key = b, next = new TreeMap() };
                    newChain.prev = chain; newChain.next.prev = newChain;

                    TreeMap newChain2 =
                        new TreeMap() { Key = chain.Key, next = chain.next, IsBoundary = chain.IsBoundary, Value = chain.Value, Index = chain.Index };
                    newChain2.prev = chain; newChain2.next.prev = newChain2;

                    if (b < chain.Key) {
                        _Next.Add(newChain);
                        _Next.Add(newChain2);
                    } else {
                        _Next.Add(newChain2);
                        _Next.Add(newChain);
                    }

                    chain.Key = null; chain.next = null;
                    chain.IsBoundary = false; chain.Value = null;
                    chain.Next = _Next;

                    return newChain.next;
                }
            } else if (chain.Key == null && chain.Next != null) {
                List<TreeMap> _Next = chain.Next;
                for (int j = 0; j < _Next.Count; j++) {
                    if (b == _Next[j].Key) {
                        if (_Next[j].next == null) {
                            _Next[j].next = new TreeMap();
                            _Next[j].next.prev = chain;
                        }
                        return _Next[j].next;
                    } else if (b > _Next[j].Key) {
                        continue;
                    } else {
                        TreeMap newchain = new TreeMap() { Key = b, next = new TreeMap() };
                        newchain.prev = chain; newchain.next.prev = newchain;

                        _Next.Insert(j, newchain);
                        return newchain.next;
                    }
                }

                TreeMap newChain = new TreeMap() { Key = b, next = new TreeMap() };
                newChain.prev = chain; newChain.next.prev = newChain;
                _Next.Add(newChain);
                return newChain.next;
            } else {
                throw new Exception("Chain Error");
            }
        }

        public TreeMap Create(string V) {
            return
                this.Create(V, (object)null);
        }

        public TreeMap Create(string V, object value) {
            return
                this.Create(Encoding.UTF8.GetBytes(V), value);
        }

        public TreeMap Create(Type T, object value) {
            return this.Create(T.GetHashCode(), value);
        }

        public TreeMap Create(int v, object value) {
            return this.Create(BitConverter.GetBytes(v), value);
        }

        public TreeMap Create(byte[] B, object Value) {
            return this.Create(B, -1, Value);
        }

        public TreeMap Create(byte[] B, int index, object Value) {
            TreeMap chain = this;

            for (int i = 0; i < B.Length; i++) {
                chain = this.Create(B[i], chain);
            }

            chain.prev.Index = index;
            chain.prev.Value = Value;
            chain.prev.IsBoundary = true;

            return chain;
        }

        public TreeMap Create(byte[] B) {
            return this.Create(B, null);
        }

        public TreeMap Find(byte b) {
            byte? _value = this.Key;
            List<TreeMap> _next = this.Next;
            if (_value == null & _next == null) {
                return null;
            } else if (_value != null /*&& _next == null*/) {
                return
                    _value == b ? this.next : null;
            } else if (/*_value == null &&*/ _next != null) {
                if (_next.Count == 256) {
                    return _next[b].next;
                }

                for (int i = 0; i < _next.Count; i++) {
                    int min = 0, max = _next.Count - 1, mid = (min + max) / 2;
                    byte? v = null;
                    do {
                        v = _next[mid].Key;
                        if (b > v) {
                            min = mid + 1; mid = (min + max) / 2;
                        } else if (b < v) {
                            max = mid - 1; mid = (min + max) / 2;
                        } else if (v == b) {
                            return _next[mid].next;
                        } else {
                            return null;
                        }

                    } while (min <= max && b != v);

                }

                return null;
            } else/* if (_value != null && _next != null)*/ {
                throw new CoreException();
            }
        }

        public int FindIndex(byte b) {
            TreeMap tree = this.Find(b);
            if (tree == null) {
                return -1;
            }

            return tree.prev.Index;
        }

        public TreeMap Find(Type T) {
            return
                this.Find(T.GetHashCode());
        }

        public TreeMap Find(int v) {
            return
                this.Find(BitConverter.GetBytes(v));
        }

        public TreeMap Find(byte[] B) {
            return this.Find(B, 0, B.Length, false);
        }

        public TreeMap Find(byte[] B, int init, int len) {
            return Find(B, init, len, false);
        }

        public TreeMap Find(byte[] B, int init, int len, bool toLower) {
            TreeMap _next = this; int len_max = init + len;
            for (int i = init; i < len_max; i++) {
                byte b = B[i];
                if (toLower && (b > 64 && b < 91)) {
                    b += 32;
                }
                _next = _next.Find(b);
                if (_next == null) {
                    return null;
                }
            }
            if (_next == null) {
                return null;
            }
            return _next.prev;
        }

        public static TreeMap Create(byte[][] B) {
            TreeMap tree = new TreeMap();
            for (int i = 0; i < B.Length; i++) {
                tree.Create(B[i], i, null);
            }

            return tree;
        }

        public static TreeMap Create(params string[] V) {
            if (V == null || V.Length == 0) {
                return null;
            }

            TreeMap tree = new TreeMap();
            for (int i = 0, len_i = V.Length; i < len_i; i++) {
                byte[] B =
                    Encoding.UTF8.GetBytes(V[i]);
                for (int j = 0, len_j = B.Length; j < len_j; j++) {
                    tree.Create(B, j, null);
                }
            }

            return tree;
        }
    }
}